package org.linlinjava.litemall.admin.service;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.express.WxMaExpressDelivery;
import cn.binarywang.wx.miniapp.bean.express.WxMaExpressPath;
import cn.binarywang.wx.miniapp.bean.express.request.*;
import cn.binarywang.wx.miniapp.bean.express.result.WxMaExpressOrderInfoResult;
import cn.binarywang.wx.miniapp.constant.WxMaConstants;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.linlinjava.litemall.core.express.WxExpressService;
import org.linlinjava.litemall.core.kdniao.dto.Order;
import org.linlinjava.litemall.core.kdniao.service.KdniaoService;
import org.linlinjava.litemall.core.notify.NotifyService;
import org.linlinjava.litemall.core.notify.NotifyType;
import org.linlinjava.litemall.core.util.JacksonUtil;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.root.DetailBase;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.db.util.BalanceConstant;
import org.linlinjava.litemall.db.util.OrderUtil;
import org.linlinjava.litemall.db.util.ShipWayConstant;
import org.linlinjava.litemall.db.util.SpellConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

import static org.linlinjava.litemall.admin.util.AdminResponseCode.*;
import static org.linlinjava.litemall.db.util.RentOrderConstant.STATUS_SHIP;
import static org.linlinjava.litemall.db.util.RentOrderConstant.STATUS_WAIT;

@Service

public class AdminOrderService {
    private final Log logger = LogFactory.getLog(AdminOrderService.class);

    @Autowired
    private LitemallOrderGoodsService orderGoodsService;
    @Autowired
    private LitemallOrderService orderService;
    @Autowired
    private LitemallGoodsProductService productService;
    @Autowired
    private LitemallUserService userService;
    @Autowired
    private LitemallCommentService commentService;
    @Autowired
    private LitemallWxExpressService litemallWxExpressService;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private NotifyService notifyService;
    @Autowired
    private LogHelper logHelper;
    @Autowired
    private WxMaService wxMaService;
    @Autowired
    private LitemallAddressService addressService;
    @Autowired
    private WxExpressService wxExpressService;
    @Autowired
    private LitemallSpellService spellService;
    @Autowired
    private AdminSpellService adminSpellService;
    @Autowired
    private KdniaoService kdniaoService;
    @Autowired
    private LitemallRentOrderService litemallRentOrderService;

    public Object list(String nickname, String orderSn, String start, String end, List<Short> orderStatusArray,
                       Integer page, Integer limit, String sort, String order ,String bookName) {
        List<LitemallOrder> orderList = orderService.querySelective(nickname, orderSn, start, end, orderStatusArray, page, limit,
                sort, order,bookName);
        return ResponseUtil.okList(orderList);
    }

    public Object detail(Integer id) {
        LitemallOrder order = orderService.findById(id);
        List<LitemallOrderGoods> orderGoods = orderGoodsService.queryByOid(id);
        UserVo user = userService.findUserVoById(order.getUserId());
        LitemallSpell spell = spellService.queryByOrderId(id);
        Map<String, Object> data = new HashMap<>();
        data.put("order", order);
        data.put("orderGoods", orderGoods);
        data.put("user", user);
        data.put("spell", spell);
        return ResponseUtil.ok(data);
    }

    /**
     * 订单退款
     * <p>
     * 1. 检测当前订单是否能够退款;
     * 2. 微信退款操作;
     * 3. 设置订单退款确认状态；
     * 4. 订单商品库存回库。
     * <p>
     * TODO
     * 虽然接入了微信退款API，但是从安全角度考虑，建议开发者删除这里微信退款代码，采用以下两步走步骤：
     * 1. 管理员登录微信官方支付平台点击退款操作进行退款
     * 2. 管理员登录litemall管理后台点击退款操作进行订单状态修改和商品库存回库
     *
     * @param body 订单信息，{ orderId：xxx }
     * @return 订单退款操作结果
     */
    @Transactional
    public Object refund(String body) {
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        String refundMoney = JacksonUtil.parseString(body, "refundMoney");
        if (orderId == null) {
            return ResponseUtil.badArgument();
        }
        if (StringUtils.isEmpty(refundMoney)) {
            return ResponseUtil.badArgument();
        }

        LitemallOrder order = orderService.findById(orderId);
        if (order == null) {
            return ResponseUtil.badArgument();
        }

        if (order.getActualPrice().compareTo(new BigDecimal(refundMoney)) != 0) {
            return ResponseUtil.badArgumentValue();
        }

        // 如果订单不是退款状态，则不能退款
        if (!order.getOrderStatus().equals(OrderUtil.STATUS_REFUND)) {
            return ResponseUtil.fail(ORDER_CONFIRM_NOT_ALLOWED, "订单不能退款");
        }

        // 如果发起拼单且已结束则不可退款
//        LitemallSpell creator = spellService.queryInitiatorByOrderId(orderId);
//        if (creator!=null && creator.getStatus().equals(SpellConstant.STATUS_SUCCESS)) {
//            return ResponseUtil.fail(ORDER_CONFIRM_NOT_ALLOWED, "订单已发起拼单不能退款");
//        }

        if (order.getPayId()!=null) {// 微信退款
            WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
            wxPayRefundRequest.setOutTradeNo(order.getOrderSn());
            wxPayRefundRequest.setOutRefundNo("refund_" + order.getOrderSn());
            // 元转成分
            Integer totalFee = order.getActualPrice().multiply(new BigDecimal(100)).intValue();
            wxPayRefundRequest.setTotalFee(totalFee);
            wxPayRefundRequest.setRefundFee(totalFee);

            WxPayRefundResult wxPayRefundResult;
            try {
                wxPayRefundResult = wxPayService.refund(wxPayRefundRequest);
            } catch (WxPayException e) {
                logger.error(e.getMessage(), e);
                return ResponseUtil.fail(ORDER_REFUND_FAILED, "订单退款失败");
            }
            if (!wxPayRefundResult.getReturnCode().equals("SUCCESS")) {
                logger.warn("refund fail: " + wxPayRefundResult.getReturnMsg());
                return ResponseUtil.fail(ORDER_REFUND_FAILED, "订单退款失败");
            }
            if (!wxPayRefundResult.getResultCode().equals("SUCCESS")) {
                logger.warn("refund fail: " + wxPayRefundResult.getReturnMsg());
                return ResponseUtil.fail(ORDER_REFUND_FAILED, "订单退款失败");
            }
            order.setRefundType("微信退款接口");
            order.setRefundContent(wxPayRefundResult.getRefundId());
        } else { // 余额退款
            userService.addBalance(order.getUserId(), order.getActualPrice(), BalanceConstant.REFUND);
        }


        LocalDateTime now = LocalDateTime.now();
        // 设置订单取消状态
        order.setOrderStatus(OrderUtil.STATUS_REFUND_CONFIRM);
        order.setEndTime(now);
        // 记录订单退款相关信息
        order.setRefundAmount(order.getActualPrice());
        order.setRefundTime(now);
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            throw new RuntimeException("更新数据已失效");
        }

        // 商品货品数量增加
        List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId);
        for (LitemallOrderGoods orderGoods : orderGoodsList) {
            Integer productId = orderGoods.getProductId();
            Integer number = orderGoods.getNumber();
            if (productService.addStock(orderGoods.getGoodsId(), number) == 0) {
                throw new RuntimeException("商品货品库存增加失败");
            }
        }

//        // 如果有拼单则拼单失败，有奖励则收回奖励
//        LitemallSpell spell = spellService.queryByOrderId(orderId);
//        // 拼单失败
//        adminSpellService.fail(spell.getId());

//        // 收回获取积分
//        memberService.cutBonus(order.getUserId(), order.getBonus(), "退款");
        //TODO 发送邮件和短信通知，这里采用异步发送
        // 退款成功通知用户, 例如“您申请的订单退款 [ 单号:{1} ] 已成功，请耐心等待到账。”
        // 注意订单号只发后6位
        notifyService.notifySmsTemplate(order.getMobile(), NotifyType.REFUND,
                new String[]{order.getOrderSn().substring(8, 14)});

        logHelper.logOrderSucceed("退款", "订单编号 " + order.getOrderSn());
        return ResponseUtil.ok();
    }

    /**
     * 发货
     * 1. 检测当前订单是否能够发货
     * 2. 设置订单发货状态
     *
     * @param body 订单信息，{ orderId：xxx, shipSn: xxx, shipChannel: xxx }
     * @return 订单操作结果
     * 成功则 { errno: 0, errmsg: '成功' }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    public Object ship(String body) {
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        String shipSn = JacksonUtil.parseString(body, "shipSn");
        String shipChannel = JacksonUtil.parseString(body, "shipChannel");
        if (orderId == null || shipSn == null || shipChannel == null) {
            return ResponseUtil.badArgument();
        }

        LitemallOrder order = orderService.findById(orderId);
        if (order == null) {
            return ResponseUtil.badArgument();
        }

        // 如果订单不是已付款状态，则不能发货
        if (!order.getOrderStatus().equals(OrderUtil.STATUS_PAY)) {
            return ResponseUtil.fail(ORDER_CONFIRM_NOT_ALLOWED, "订单不能确认收货");
        }

        order.setOrderStatus(OrderUtil.STATUS_SHIP);
        order.setShipSn(shipSn);
        order.setShipChannel(shipChannel);
        order.setShipTime(LocalDateTime.now());
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            return ResponseUtil.updatedDateExpired();
        }

        //TODO 发送邮件和短信通知，这里采用异步发送
        // 发货会发送通知短信给用户:          *
        // "您的订单已经发货，快递公司 {1}，快递单 {2} ，请注意查收"
        notifyService.notifySmsTemplate(order.getMobile(), NotifyType.SHIP, new String[]{shipChannel, shipSn});

        logHelper.logOrderSucceed("发货", "订单编号 " + order.getOrderSn());
        return ResponseUtil.ok();
    }

    /**
     * 微信物流助手发货
     * 1. 检测当前订单是否能够发货
     * 2. 设置订单发货状态
     *
     * @param body 订单信息，{ orderId：xxx, deliveryId: xxx, serviceType: xxx, serviceTypeName: XXX, customRemark: XXX }
     * @return 订单操作结果
     * 成功则 { errno: 0, errmsg: '成功' }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    public Object wxShip(String body) {
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        String deliveryId = JacksonUtil.parseString(body, "deliveryId");
        Integer serviceType = JacksonUtil.parseInteger(body, "serviceType");
        String serviceTypeName = JacksonUtil.parseString(body, "serviceTypeName");
        String  customRemark = JacksonUtil.parseString(body, "customRemark");
        if (orderId == null || deliveryId == null || serviceType == null) {
            return ResponseUtil.badArgument();
        }

        LitemallOrder order = orderService.findById(orderId);
        if (order == null) {
            return ResponseUtil.badArgument();
        }

        // 如果订单不是已付款状态，则不能发货
        if (!order.getOrderStatus().equals(OrderUtil.STATUS_PAY)) {
            return ResponseUtil.fail(ORDER_CONFIRM_NOT_ALLOWED, "订单不能确认收货");
        }

        Integer userId = order.getUserId();
        LitemallUser user = userService.findById(userId);
        if (user==null && user.getWeixinOpenid() == null) {
            return ResponseUtil.fail(ORDER_CONFIRM_NOT_ALLOWED, "订单微信用户不存在");
        }

        /***对接微信物流助手接口start***/
        WxMaExpressAddOrderRequest.WxMaExpressAddOrderRequestBuilder builder = WxMaExpressAddOrderRequest.builder();
        // 基础信息
        builder.addSource(WxMaConstants.OrderAddSource.MINI_PROGRAM); // 固定
        builder.orderId(orderId.toString()); //orderId
        builder.openid(user.getWeixinOpenid()); //收件人openid
        builder.customRemark(customRemark); // 备注
        // 发件人信息
        wxExpressService.setSystemSender(builder);
        // 收件人信息
        wxExpressService.setReceiver(builder, order);
        // 包裹信息
        List<? extends DetailBase> litemallOrderGoods = orderGoodsService.queryByOid(orderId);
        wxExpressService.setInfo(builder, litemallOrderGoods, "/pages/ucenter/orderDetail/orderDetail?id=" + orderId);
        // 保价信息
        wxExpressService.setDefaultInsured(builder);
        // 物流服务信息
        wxExpressService.setService(builder);
        //发送请求
        WxMaExpressOrderInfoResult result;
        try {
            WxMaExpressAddOrderRequest wxMaExpressAddOrderRequest = builder.build();
            result = wxMaService.getExpressService().addOrder(wxMaExpressAddOrderRequest);
            System.out.println(result);
        } catch (WxErrorException e) {
            return ResponseUtil.fail(400, "对接微信物流助手失败");
        }
        /***对接微信物流助手接口end***/

        order.setOrderStatus(OrderUtil.STATUS_SHIP);
        order.setShipWay(ShipWayConstant.SHIP_WAY_SELF);
        order.setShipSn(result.getWaybillId());
        order.setShipChannel(deliveryId);
        order.setShipTime(LocalDateTime.now());
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            return ResponseUtil.updatedDateExpired();
        }

        //TODO 发送邮件和短信通知，这里采用异步发送
        // 发货会发送通知短信给用户:          *
        // "您的订单已经发货，快递公司 {1}，快递单 {2} ，请注意查收"
        notifyService.notifySmsTemplate(order.getMobile(), NotifyType.SHIP, new String[]{deliveryId, result.getWaybillId()});

        logHelper.logOrderSucceed("发货", "订单编号 " + order.getOrderSn());

        //TODO 测试轨迹
        wxExpressService.testTrace(orderId.toString(), result.getWaybillId());

        return ResponseUtil.ok();
    }

    /**
     * 客户前期自送或自己联系物流
     * @param shipWay
     * @param shipperCode
     * @param logisticCode
     * @param orderId
     * @return
     */
    public Object orderShip(Integer shipWay,String shipperCode,String logisticCode,Integer orderId) {
        LitemallOrder order = orderService.findById(orderId);
        if (order == null) {
            return ResponseUtil.fail(400,"该订单不存在");
        }
        if (!order.getOrderStatus().equals(OrderUtil.STATUS_PAY)) {
            return ResponseUtil.fail(400,"该订单不能发货");
        }
        switch (shipWay){
            case 1:
                order.setShipWay((1));
                order.setOrderStatus(OrderUtil.STATUS_SHIP);
                order.setShipTime(LocalDateTime.now());
                break;
            case 2:
                order.setShipWay(2);
                if (StringUtils.isEmpty(shipperCode) || StringUtils.isEmpty(logisticCode)) {
                    return ResponseUtil.fail(400,"物流公司编号和物流单号不能为空");
                }
                order.setShipChannel(shipperCode);
                String shipName = litemallWxExpressService.queryByDeliveryId(shipperCode).getName();
                order.setShipChannelName(shipName);
                order.setShipSn(logisticCode);
                order.setOrderStatus(OrderUtil.STATUS_SHIP);
                order.setOrderStatus(OrderUtil.STATUS_SHIP);
                order.setShipTime(LocalDateTime.now());
                break;
            default:
                return ResponseUtil.fail(500,"shipWay 只能为1 或 2");
        }
        orderService.updateById(order);
        return order;

    }

    public Object getExpressTrace(Integer orderId) {
        LitemallOrder order = orderService.findById(orderId);
        if (order == null) {
            return ResponseUtil.fail(400,"该订单不存在");
        }
        if (order.getShipWay().equals(1)) {
            return ResponseUtil.ok("同城配送，今日必达！");
        }
        try {
            return ResponseUtil.ok(kdniaoService.getOrderTracesByJson(new Order(order.getOrderSn(),order.getShipChannel(),order.getShipSn())));
        }
        catch (Exception e) {
            return ResponseUtil.fail(500,"获取物流轨迹失败");
        }
    }

    public Object getWxPath(Integer orderId) {
        LitemallOrder order = orderService.findById(orderId);
        if (order == null) {
            return ResponseUtil.badArgument();
        }
        LitemallUser user = userService.findById(order.getUserId());
        try {
            WxMaExpressPath path = wxExpressService.getPath(order.getShipSn(), order.getShipChannel(), user.getWeixinOpenid(), orderId.toString());
            return ResponseUtil.ok(path);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return ResponseUtil.fail();
        }
    }


    /**
     * 回复订单商品
     *
     * @param body 订单信息，{ orderId：xxx }
     * @return 订单操作结果
     * 成功则 { errno: 0, errmsg: '成功' }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    public Object reply(String body) {
        Integer commentId = JacksonUtil.parseInteger(body, "commentId");
        if (commentId == null || commentId == 0) {
            return ResponseUtil.badArgument();
        }
        // 目前只支持回复一次
        LitemallComment comment = commentService.findById(commentId);
        if(comment == null){
            return ResponseUtil.badArgument();
        }
        if (!StringUtils.isEmpty(comment.getAdminContent())) {
            return ResponseUtil.fail(ORDER_REPLY_EXIST, "订单商品已回复！");
        }
        String content = JacksonUtil.parseString(body, "content");
        if (StringUtils.isEmpty(content)) {
            return ResponseUtil.badArgument();
        }
        // 更新评价回复
        comment.setAdminContent(content);
        commentService.updateById(comment);

        return ResponseUtil.ok();
    }

    public Object getRentOderLife(Integer orderId) {
       List<LitemallRentOrderChange> list =litemallRentOrderService.getRentOderLife(orderId);
        return ResponseUtil.okList(list);
    }
}
